package sk.datalan.similarity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.openrdf.model.Statement;

import sk.datalan.similarity.predicates.Area;
import sk.datalan.similarity.predicates.Balcony;
import sk.datalan.similarity.predicates.DwellingPartArea;
import sk.datalan.similarity.predicates.EntireFloorArea;
import sk.datalan.similarity.predicates.EntireLandArea;
import sk.datalan.similarity.predicates.EntireUsageArea;
import sk.datalan.similarity.predicates.Image;
import sk.datalan.similarity.predicates.Material;
import sk.datalan.similarity.predicates.ObjectStatus;
import sk.datalan.similarity.predicates.Predicate;
import sk.datalan.similarity.predicates.StreetNumber;
import sk.datalan.similarity.predicates.Terrace;

public final class Individual {
	public static int count = 0;
	private final String id;
	private HashMap<String, List<Predicate>> predicate = new HashMap<String, List<Predicate>>( 16 );
	private List<String> candicates = new ArrayList<String>( 200 );

	public Individual( String id, Statement s ) {
		this.id = id;
		addElement( s );
	}

	/*
	 * Add predicate to RealEstate individual
	 */
	public void addElement( Statement s ) {
		ArrayList<Predicate> temp = new ArrayList<Predicate>( 10 );
		if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#sameRealestateAsCandidate".equals( s.getPredicate().stringValue() ) ) {
			this.candicates.add( s.getObject().stringValue() );
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#area".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new Area( s.getObject().stringValue() ) );
			} else {
				temp.add( new Area( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#entireFloorArea".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new EntireFloorArea( s.getObject().stringValue() ) );
			} else {
				temp.add( new EntireFloorArea( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#dwellingPartArea".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new DwellingPartArea( s.getObject().stringValue() ) );
			} else {
				temp.add( new DwellingPartArea( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#entireLandArea".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new EntireLandArea( s.getObject().stringValue() ) );
			} else {
				temp.add( new EntireLandArea( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#entireUsageArea".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new EntireUsageArea( s.getObject().stringValue() ) );
			} else {
				temp.add( new EntireUsageArea( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#imageHash".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new Image( s.getObject().stringValue() ) );
			} else {
				temp.add( new Image( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#objectStatus".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new ObjectStatus( s.getObject().stringValue() ) );
			} else {
				temp.add( new ObjectStatus( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#streetNumber".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new StreetNumber( s.getObject().stringValue() ) );
			} else {
				temp.add( new StreetNumber( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#hasBalcony".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new Balcony( s.getObject().stringValue() ) );
			} else {
				temp.add( new Balcony( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#hasTerrace".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new Terrace( s.getObject().stringValue() ) );
			} else {
				temp.add( new Terrace( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else if ( "http://www.datalan.sk/semweb/ontology/realestate/1.0/realestate.owl#material".equals( s.getPredicate().stringValue() ) ) {
			if ( this.predicate.containsKey( s.getPredicate().stringValue() ) ) {
				this.predicate.get( s.getPredicate().stringValue() ).add( new Material( s.getObject().stringValue() ) );
			} else {
				temp.add( new Material( s.getObject().stringValue() ) );
				this.predicate.put( s.getPredicate().stringValue(), temp );
			}
		} else {
			//Utils.log( "Unknown predicate : " + s.getPredicate() );
		}
	}

	public HashMap<String, List<Predicate>> getPredicates() {
		return this.predicate;
	}

	public List<String> getCandidateKeys() {
		return this.candicates;
	}

	/*
	 * Vypocita index podobnosti instancie tohto objektu s instanciou ostatnych objektov
	 */
	public double getSimilarityIndex( Individual i ) {
		double weight = 0;
		double similarity = 0;
		for ( String key : predicate.keySet() ) {
			if ( i.getPredicates().containsKey( key ) ) {
				for ( Predicate p : predicate.get( key ) ) {
					similarity += p.getSimilarityIndex( i.getPredicates().get( key ) );
					weight += p.getWeight();
					count++; //statistic counter
				}

			}
		}
		if ( weight == 0 ) {
			return 0;
		}
		return similarity / weight;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ( ( getId() == null ) ? 0 : getId().hashCode() );
		return result;
	}

	@Override
	public boolean equals( Object obj ) {
		if ( this == obj )
			return true;
		if ( obj == null )
			return false;
		if ( getClass() != obj.getClass() )
			return false;
		Individual other = (Individual) obj;
		if ( getId() == null ) {
			if ( other.getId() != null )
				return false;
		} else if ( !getId().equals( other.getId() ) )
			return false;
		return true;
	}

	public String getId() {
		return id;
	}

	public void reset() {
		for ( String key : getPredicates().keySet() ) {
			for ( Predicate p : getPredicates().get( key ) ) {
				p.reset();
			}
		}
	}
}
